﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Rappelz.GameServer
{
    public class GameRule
    {
        public static bool bIsNoCollisionCheck = false;
        public static bool bRestrictSpecialChar = false;
        public static bool bUseLoginLogoutDebug = true;
        public static bool bForceUnregisterAccountOnKickFail = true;
        public static bool bLimitFieldLogout = false;
        public static bool bLimitGameTime = false;
        public static bool bDisableCreateCharacter = false;
        public static bool bUseSecurityNoForDeletingCharacter = false;
        public static bool bUseAutoJail = false;
        public static bool bAutoOpen = false;
        public static bool bIsCashUsableServer = false;
        public static bool bIsServiceServer = false;
        public static bool bUsePlayPoint = false;
        public static bool bSkipLoadingAttribute = false;
        public static bool bChangeMonsterDropSet = false;
        public static bool bMonsterWandering = true;
        public static bool bIsPKServer = false;
        public static bool bMonsterPathFinding = true;
        public static bool bLimitDungeonEnterableLevel = false;
        public static bool bNoSkillCooltime = false;
        public static bool bIgnoreSkillCoolTime = false;
        public static bool bBroadcastEventItemPickup = true;
        public static bool bUseSecurityNoForStorage = false;
        public static bool bCheckStorageSecurityAlways = false;
        public static bool bRedNameMobsFirstAttack = true;
        public static bool bLimitAdvChatCount = true;
        public static string szUrlList = "c.guild.url|192.168.1.5/login.aspx|guild_test_download.url|upload/|web_download|192.168.1.5|web_download_port|0|shop.url|http://192.168.1.5/service/GameShopJump.aspx|ghelp_url|http://192.168.1.5/GameHelp/help.html|guild_icon_upload.ip|192.168.1.5|guild_icon_upload.port|4617|guild_icon_upload.url|http://192.168.1.5/upload/iconupload.aspx";
        public static string szServerName = "RappelzPz";
        public static string guild_icon_base_url = "http://192.168.1.5/gicons/";


        public static int nMaxGameTimeLimitedAge = 18;
        public static int nMaxTiredGameTime = 0;
        public static int nMaxHealthyGameTime = 0;
        public static uint nCurrentLocalFlag = 4;
        public static uint nSchedulerThreads = 4;
        public static uint nPeriodicalNPCAdjustment = 0;
        public static int nMaxLevel = 300;
        public static int nMaxStorageItemCount = 1000;
        public static int nCurrentEventID = 0;
        public static int nEnhanceFailType = 2;
        public static int nMinGlobalChatUsableLevel = 10;
        public static uint nItemHold = 30;
        public static int nClientVersion = 81;

        public static float fPVPDamageRateForPlayer = 0.2f;
        public static float fPVPDamageRateForSummon = 0.13f;
        public static float fAllyPCBangChaosBonusRate = 0.2f;
        public static float fPremiumPCBangChaosBonusRate = 0.1f;

        public static float fPremiumPCBangGoldBonusDropRate = 1.0f;
        public static float fPremiumPCBangItemBonusDropRate = 1.0f;
        public static float fPremiumPCBangChaosBonusDropRate = 1.0f;
        public static float fCrimeLimit = 1000.0f;
        public static float fSemiCrimeLimit = 500.0f;
        public static float fMoralLimit = 100.0f;
        public static float fSummonStatminaSaveBonusRate = 0.5f;
        public static float fEXPRate = 2000.0f;
        public static float fPartyEXPRate = 1.0f;
        public static float fStaminaBonusRate = 1.0f;
        public static float fGoldDropRate = 1.0f;
        public static float fItemDropRate = 4000.0f;
        public static float fFieldSpawnMultiply = 0.5f;
        public static float fChaosDropRate = 1.0f;

        public static uint nLogoutTimer = 0;

        public static int[] _table = new int[] {0,20,50,80,100,120,150,180};
        public static int[] _modtable = new int[] {0,3,3,2,2,3,2,2};
        public static int[] _playerExpLimit = new int[301];
        public static double[] _staminaExpRate = new double[301];

        public static bool IsBlockedAccount(string szAccount)
        {
            return false;
        }

        public static bool IsValidName(string name, int nBufferSize, int nLimitMin, int nLimitMax)
        {
            return true;
        }


        public static int GetMaxMP(float intelligence, int level, float fCM)
        {
            return (int)(intelligence * fCM * 30.0f + (float)(20 * level));
        }

        public static string AppendOnetimePassword(int one_time_key, int nSID, int nAccountID)
        {
            int r = Globals.GetRandomInt32();
            uint _esi = (uint) nSID;
            uint _ecx = (uint) one_time_key;
            uint _eax = (uint) nSID + (uint)one_time_key;
            _eax += (uint) nAccountID;
            
            _ecx = _ecx ^ 0x16EE69E8u;
            uint _edx = _ecx;
            _edx = _edx ^ (uint) nSID; // _esi
            _esi = _edx;
            _esi = _esi ^ (uint) nAccountID;
            _edx = _edx ^ 0x9DC720ACu;
            _eax = _eax ^ _esi;
            _eax = _eax ^ 0x7F9B3D2Eu;
            _esi = _esi ^ 0x31F42CB7u;
            _ecx = _ecx ^ 0x0D8FB51A9u;
            uint _edi = 0x16EE69E8u;
            return String.Format("{0:x8}{1:x8}{2:x8}{3:x8}{4:x8}", _eax, _esi, _edx, _ecx, _edi);
        }

        public static string GetString(string szName, string szDefault)
        {
            switch(szName)
            {
                case "game.newbiehelp_deva_url":
                    return "about:blank";

            }
            return szDefault;
        }

        public static int GetInt(string szName, int szDefault)
        {
            switch (szName)
            {
                case "game.ServiceServer":
                    return 0;

                case "game.PKServer":
                    return 0;

                case "auth.server_idx":
                    return 1;

            }
            return szDefault;
        }

        public static int GetRankLevel(int rank)
        {
            int idx = rank;
            if (idx < 1)
                idx = 1;
            if (idx > 8)
                idx = 8;

            switch(idx)
            {
                case 1:
                    return 0;
                case 2:
                    return 20;
                case 3:
                    return 50;
                case 4:
                    return 80;
                case 5:
                    return 100;
                case 6:
                    return 120;
                case 7:
                    return 150;
                case 8:
                    return 180;
            }

            return 0;
        }

        public static int GetItemLevelLimit(int item_rank)
        {
            return GetRankLevel(item_rank);
        }

        public static int GetItemRecommendModTable(int item_rank)
        {
            int idx = item_rank;

            if (idx < 1)
                idx = 1;
            if (idx > 8)
                idx = 8;
            return _modtable[idx];
        }

        public static int GetItemRecommendLevel(int item_rank, int item_level)
        {
            int result;

            if (item_rank > 1)
            {
                result = (GameRule.GetItemRecommendModTable(item_rank) * (item_level-1)) + GameRule.GetItemLevelLimit(item_rank);
            }
            else
            {
                result = 0;
            }
            return result;
        }

        public static float GetItemLevelPenalty(int creature_level, int item_rank, int item_level)
        {
            float result = 1;

            int recommended = GameRule.GetItemRecommendLevel(item_rank, item_level);
            int limit = GameRule.GetItemLevelLimit(item_rank);
            if (item_level == 1 || creature_level < limit || creature_level >= recommended)
            {
                result = 1;
            }
            else
            {
                float n = (float)(recommended - limit);
                result = (float)(recommended - creature_level);
                result = n * result;
//                 v6 = 0.05f * (float)item_level;
//                 v7 = (10000 - v6->value) >> 32;
//                 LODWORD(B.value) = 10000 - LODWORD(v6->value);
//                 HIDWORD(B.value) = v7;
//                 result = 10000 - c_fixed<10000>::operator_(&resulta, &n, &B)->value;
            }
            return result;
        }

        public static float GetItemValue(float item_current_value, int item_rank_value, int creature_level, int item_rank, int item_level)
        {
            float ilp = GameRule.GetItemLevelPenalty(creature_level, item_rank, item_level);
            //-,*,+
            float v8 = (item_current_value - item_rank_value) * ilp;
            return v8 + item_rank_value;
            //float f1 = item_current_value * item_rank_value;
            //return f1 * ilp;
        }

        public static float GetBowAttackPoint(float strength, float dexterity, float level, float fCM)
        {
            return ((strength * 0.4f + dexterity * 1.6f) * fCM + level);
        }

        public static float GetMaxWeight(int level, float strength)
        {
            return 10 * (level + strength);
        }

        public static float GetMagicAccuracy(float mental, float dexterity, float level, float fCM)
        {
            return ((mental * 0.4f + dexterity * 0.1f) * fCM + level);
        }

        public static int GetDecreasedEndurancePoint(int previous_endurance, int current_endurance)
        {
            return (previous_endurance + 99999) / 100000 - (current_endurance + 99999) / 100000;
        }

        public static int GetIntValueByRandomInt(double fValue)
        {
            double result = fValue + 1;
            if ((Globals.GetRandomUInt32() % 100) / 100.0 + fValue >= fValue )
                result = fValue;
            return (int) result;
        }

        public static long GetIntValueByRandomInt64(double fValue)
        {
            double result = fValue + 1;
            if ((Globals.GetRandomUInt32() % 100) / 100.0 + fValue >= fValue)
                result = fValue;
            return (long)result;
        }


        public static float GetGameTimeLimitPenalty(uint continuous_play_time)
        {
            float result = 0;

            if (!bLimitGameTime)
                result = 1.0f;
            if ( continuous_play_time >= nMaxHealthyGameTime )
            {
                if ( continuous_play_time >= nMaxTiredGameTime )
                    return result;
                return 0.5f;
            }
            else
            {
                return 1.0f;
            }
        }


        public static int GetPlayerEXPLimit(int level)
        {
            if (_playerExpLimit[level] == 0)
            {
                double p = Math.Pow(level, 1.8);
                _playerExpLimit[level] = (int)(240 - (p * -30.0) - ((240 - (p * -30.0)) * -0.1 * (level / 100)));
            }
            return _playerExpLimit[level];
        }

        public static float GetStaminaRatio(int level)
        {
            if (level < 1)
                level = 1;
            if (level > 300)
                level = 300;
            if ( 0.0 == _staminaExpRate[level])
            {
                double v2 = Math.Pow(level, 1.46) + (double)level * 2.4;
                _staminaExpRate[level] = (Math.Pow(level, 2) * 0.1 + v2 + 2.0) * 0.00055;
            }
            return (float) _staminaExpRate[level];
        }

        public static int GetPickableRange()
        {
            return 20;
        }

        public static long GetItemSellPrice(long price, int rank, int lv, bool same_price_for_buying)
        {
            long k;
            float[] f = new float[8];
            int i;

            k = price;
            if (rank <= 8)
            {
                f[0] = 1.35f;
                f[1] = 0.4f;
                f[2] = 0.2f;
                f[3] = 0.13f;
                f[4] = 0.1f;
                f[5] = 0.1f;
                f[6] = 0.1f;
                f[7] = 0.1f;
                if (lv >= 2)
                {
                    i = lv - 1;
                    do
                    {
                        if (rank != 0 && rank != 1 )
                        {
                            if ( rank == 2 )
                            {
                                k += (long)((k * 0.4f * 0.01f) * 100);
                            }
                            else
                            {
                                k += (long)((f[rank] * k * 0.001f) * 1000);
                            }
                        }
                        else
                        {
                            k += (long)((k * 1.35f * 0.1f) * 10);
                        }
                        --i;
                    }
                    while (i > 0);
                }
                if (same_price_for_buying)
                    return k;
                else
                    return k / 4;
            }
            return 0;
        }

        public static long GetSummonEXPLimit(int level)
        {
            return (long)(Math.Pow((double)level, 2.0) * 200.0);
        }

    }
}
